package com.sudo.service.admin.service.impl;

import com.github.pagehelper.PageHelper;
import com.sudo.common.constant.UserConstant;
import com.sudo.common.enums.SysStatus;
import com.sudo.common.utils.PagedGridResult;
import com.sudo.dao.admin.entity.SysRole;
import com.sudo.dao.admin.entity.SysRoleButton;
import com.sudo.dao.admin.entity.SysRoleMenu;
import com.sudo.dao.admin.entity.SysUserRole;
import com.sudo.dao.admin.mapper.*;
import com.sudo.dao.admin.model.bo.*;
import com.sudo.dao.admin.model.dto.OnlineUserDTO;
import com.sudo.dao.admin.model.vo.SysSimpleRoleButtonVO;
import com.sudo.dao.admin.model.vo.SysRoleVO;
import com.sudo.service.admin.service.AdminBaseService;
import com.sudo.service.admin.service.SysRedisAuthService;
import com.sudo.service.admin.service.SysRoleService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * @author 为道日损 2020-04-25 18:33
 */
@Service
public class SysRoleServiceImpl extends AdminBaseService implements SysRoleService {

    @Resource
    private SysRedisAuthService sysRedisAuthService;
    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;
    @Resource
    private SysRoleMapperCustom sysRoleMapperCustom;

    @Resource
    private SysRoleButtonMapper sysRoleButtonMapper;
    @Resource
    private SysUserRoleMapper sysUserRoleMapper;
    /**
     * 分页查询所有角色，条件=用户名或角色名
     * @param sysRoleQueryBO 每页的数量
     * @return list
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public PagedGridResult querySysRoleByPage(SysRoleQueryBO sysRoleQueryBO) {

        PageHelper.startPage(sysRoleQueryBO.getPage(), sysRoleQueryBO.getLimit());
        Example example = new Example(SysRole.class);
        example.orderBy(SysRole.Field.id).desc();
        Example.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(sysRoleQueryBO.getRoleName())) {
            criteria.andLike(SysRole.Field.roleName,"%"+sysRoleQueryBO.getRoleName()+"%");
        }
        if (StringUtils.isNotBlank(sysRoleQueryBO.getRoleCode())) {
            criteria.andEqualTo(SysRole.Field.roleCode,sysRoleQueryBO.getRoleCode());
        }
        if (StringUtils.isNotBlank(sysRoleQueryBO.getStatus())) {
            criteria.andEqualTo(SysRole.Field.status,sysRoleQueryBO.getStatus());
        }
        List<SysRole> sysRoleList = sysRoleMapper.selectByExample(example);
        return setterPagedGrid(sysRoleList ,sysRoleQueryBO.getPage());
    }

    /**
     * 通过roleCode查找角色
     * @param roleCode 角色代码
     * @return SysRole
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public SysRole getSysRoleByRoleCode(String roleCode) {
        Example example = new Example(SysRole.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(SysRole.Field.roleCode, roleCode);
        return sysRoleMapper.selectOneByExample(example);
    }

    /**
     * 修改角色
     * @param sysRoleUpdateBO 角色参数
     * @return 影响行数
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int updateSysRoleByCode(SysRoleUpdateBO sysRoleUpdateBO) {
        //查询原始数据
        SysRole oldSysRole = getSysRoleByRoleCode(sysRoleUpdateBO.getRoleCode());
        SysRole sysRole = new SysRole();
        BeanUtils.copyProperties(sysRoleUpdateBO, sysRole, SysRole.Field.roleCode);
        boolean isEqual = SysStatus.ON.name().equals(sysRole.getStatus());
        if (!isEqual) {
            sysRole.setStatus(SysStatus.OFF.name());
        }

        Example example = new Example(SysRole.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(SysRole.Field.roleCode, sysRoleUpdateBO.getRoleCode());

        int affectCount = sysRoleMapper.updateByExampleSelective(sysRole, example);

        //====== redis ======
        if (affectCount > 0 && (!oldSysRole.getStatus().equals(sysRoleUpdateBO.getStatus()))) {
                String roleCode = oldSysRole.getRoleCode();
                if (isEqual) {
                    sysRedisAuthService.setRedisRoleStatus(roleCode,SysStatus.ON.name());
                } else {
                    sysRedisAuthService.setRedisRoleStatus(roleCode,SysStatus.OFF.name());
                }

        }
        return affectCount;

    }


    /**
     * 获取所有角色的code和name
     * @return list
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public List<SysRole> getAllSysRoleCodeAndNameWithoutSuperByStatus(String status) {
        Example example = new Example(SysRole.class);
        example.selectProperties(SysRole.Field.roleName, SysRole.Field.roleCode);
        Example.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(status)) {
            criteria.andEqualTo(SysRole.Field.status, status);
        }
        return sysRoleMapper.selectByExample(example);
    }

    /**
     * 分页获取一个简单角色列表（角色名，代码）
     * @param sysSimpleRoleBO 查询条件
     * @return pageResult
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public PagedGridResult getSimpleRoleByPage(SysSimpleRoleBO sysSimpleRoleBO) {
        PageHelper.startPage(sysSimpleRoleBO.getPage(), sysSimpleRoleBO.getLimit());
        List<SysRoleVO> sysRoleVOList = sysRoleMapperCustom.getSimpleRole(sysSimpleRoleBO);
        return setterPagedGrid(sysRoleVOList,sysSimpleRoleBO.getPage());
    }

    /**
     * 添加角色
     * @param sysRoleAddBO 角色参数
     * @return int
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int addSysRole(SysRoleAddBO sysRoleAddBO) {
        SysRole sysRole = new SysRole();
        BeanUtils.copyProperties(sysRoleAddBO, sysRole);
        int affectCount = sysRoleMapper.insertSelective(sysRole);

        if (affectCount > 0) {
            sysRedisAuthService.setRedisRoleStatus(sysRole.getRoleCode(),sysRole.getStatus());
        }

        return affectCount;
    }


    /**
     * 判断数据库中是否已存在相同的roleCode
     * @param roleCode 角色Code
     * @return boolean
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public boolean hasRoleCode(String roleCode){
        Example example = new Example(SysRole.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(SysRole.Field.roleCode, roleCode);
        List<SysRole> sysRoleList = sysRoleMapper.selectByExample(example);
        return !CollectionUtils.isEmpty(sysRoleList);
    }

    /**
     * 通过roleCode获取角色拥有权限的菜单code
     * @param roleCode 角色code
     * @return list
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public Map<String, String> getMyMenuCodeByRoleCode(String roleCode) {
        List<SysRoleMenu> sysRoleMenuList = sysRoleMapperCustom.getMyMenuCodeByRoleCode(roleCode);
        Map<String, String> stringMap = new HashMap<>();
        for (SysRoleMenu sysRoleMenu : sysRoleMenuList) {
            stringMap.put(sysRoleMenu.getMenuCode(), sysRoleMenu.getRoleCode());
        }
        return stringMap;
    }

    /**
     * 禁用（即删除）角色-菜单权限，同时也要禁用（删除）菜单对应的按钮权限
     * @param sysRoleMenuAuthBO
     * @return int
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int offRoleMenuAuth(SysRoleMenuAuthBO sysRoleMenuAuthBO) {
        Example example1 = new Example(SysRoleMenu.class);
        Example.Criteria criteria1 = example1.createCriteria();
        criteria1.andEqualTo(SysRoleMenu.Field.roleCode, sysRoleMenuAuthBO.getRoleCode());
        criteria1.andEqualTo(SysRoleMenu.Field.menuCode, sysRoleMenuAuthBO.getMenuCode());

        //删除角色对应的菜单下的按钮权限
        Example example2 = new Example(SysRoleButton.class);
        Example.Criteria criteria2 = example2.createCriteria();
        criteria2.andEqualTo(SysRoleButton.Filed.roleCode, sysRoleMenuAuthBO.getRoleCode());
        criteria2.andEqualTo(SysRoleButton.Filed.menuCode, sysRoleMenuAuthBO.getMenuCode());
        sysRoleButtonMapper.deleteByExample(example2);

        int affectCount = sysRoleMenuMapper.deleteByExample(example1);

        //====== redis ======
        // redis_role_permission (删除可用角色-可用菜单)
        if (affectCount > 0) {
            sysRedisAuthService.delRedisRolePermissionFromRedis(sysRoleMenuAuthBO.getRoleCode(), sysRoleMenuAuthBO.getMenuCode(),null);
        }
        return affectCount;
    }

    /**
     * 启用（即新增）角色菜单权限
     * @param sysRoleMenuAuthBO
     * @return int
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int onRoleMenuAuth(SysRoleMenuAuthBO sysRoleMenuAuthBO) {
        SysRoleMenu sysRoleMenu = new SysRoleMenu();
        sysRoleMenu.setRoleCode(sysRoleMenuAuthBO.getRoleCode());
        sysRoleMenu.setMenuCode(sysRoleMenuAuthBO.getMenuCode());

        int affectCount = sysRoleMenuMapper.insert(sysRoleMenu);

        //====== redis ======
        // redis_menu_button (新增可用菜单.可用按钮*)
        if (affectCount > 0) {
            //新增redis中角色菜单权限
            List<SysSimpleRoleButtonVO> sysSimpleRoleButtonVOList = sysRoleMapperCustom.getRoleMenuButtonAuth(sysRoleMenuAuthBO.getRoleCode(), sysRoleMenuAuthBO.getMenuCode());
            if (CollectionUtils.isEmpty(sysSimpleRoleButtonVOList)) {
                sysRedisAuthService.setRedisRolePermissionToRedis(sysRoleMenuAuthBO.getRoleCode(), sysRoleMenuAuthBO.getMenuCode(), UserConstant.NONE);
            } else {
                sysRedisAuthService.setRedisRolePermissionToRedis(sysSimpleRoleButtonVOList);
            }
        }
        return affectCount;
    }

    /**
     * 禁用（即删除）角色按钮权限
     * @param sysRoleButtonAuthBO 角色 菜单 按钮
     * @return int
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int offRoleButtonAuth(SysRoleButtonAuthBO sysRoleButtonAuthBO) {
        Example example = new Example(SysRoleButton.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(SysRoleButton.Filed.roleCode, sysRoleButtonAuthBO.getRoleCode());
        criteria.andEqualTo(SysRoleButton.Filed.menuCode, sysRoleButtonAuthBO.getMenuCode());
        criteria.andEqualTo(SysRoleButton.Filed.buttonCode, sysRoleButtonAuthBO.getButtonCode());
        int affectCount = sysRoleButtonMapper.deleteByExample(example);

        //====== redis ======
        // redis_role_permission (删除可用角色-可用菜单)
        if (affectCount > 0) {
            sysRedisAuthService.delRedisRolePermissionFromRedis(sysRoleButtonAuthBO.getRoleCode(), sysRoleButtonAuthBO.getMenuCode(), sysRoleButtonAuthBO.getButtonCode());
        }
        return affectCount;
    }

    /**
     * 启用（即新增）角色按钮权限
     * @param sysRoleButtonAuthBO 角色 菜单 按钮
     * @return int
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int onRoleButtonAuth(SysRoleButtonAuthBO sysRoleButtonAuthBO) {
        SysRoleButton sysRoleButton = new SysRoleButton();
        sysRoleButton.setButtonCode(sysRoleButtonAuthBO.getButtonCode());
        sysRoleButton.setRoleCode(sysRoleButtonAuthBO.getRoleCode());
        sysRoleButton.setMenuCode(sysRoleButtonAuthBO.getMenuCode());

        int affectCount = sysRoleButtonMapper.insert(sysRoleButton);
        //====== redis ======
        // redis_role_permission (删除可用角色-可用菜单)
        if (affectCount > 0) {
            //新增redis中角色菜单权限
            sysRedisAuthService.setRedisRolePermissionToRedis(sysRoleButtonAuthBO.getRoleCode(),sysRoleButtonAuthBO.getMenuCode(),sysRoleButtonAuthBO.getButtonCode());
        }
        return affectCount;
    }

    /**
     * 通过用户名获取角色
     * @param username 用户名
     * @return sysRole
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public SysRole getRoleByUsername(String username) {
        Example example = new Example(SysUserRole.class);
        example.selectProperties(SysUserRole.Field.roleCode);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(SysUserRole.Field.username,username);
        SysUserRole sysUserRole = sysUserRoleMapper.selectOneByExample(example);

        Example example1 = new Example(SysRole.class);
        Example.Criteria criteria1 = example1.createCriteria();
        criteria1.andEqualTo(SysRole.Field.roleCode,sysUserRole.getRoleCode());
        return sysRoleMapper.selectOneByExample(example1);
    }

    /**
     * 通过用户名查找对用的角色Code
     * @param username 用户名
     * @return roleCode
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public String getRoleCodeByUsername(String username) {

        Example example = new Example(SysUserRole.class);
        example.selectProperties(SysUserRole.Field.roleCode);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(SysUserRole.Field.username, username);
        SysUserRole sysUserRole = sysUserRoleMapper.selectOneByExample(example);
        return sysUserRole.getRoleCode();
    }

    /**
     *通过角色代码查找对应的用户数量
     * @param roleCode 角色Code
     * @return 用户数
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public int getUserCountByRoleCode(String roleCode) {
        Example example = new Example(SysUserRole.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(SysUserRole.Field.roleCode, roleCode);
        return sysUserRoleMapper.selectCountByExample(example);
    }

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int deleteSysRoleByRoleCode(String roleCode) {
        Example example = new Example(SysRole.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(SysRole.Field.roleCode, roleCode);

        //删除角色-菜单
        Example example1 = new Example(SysRoleMenu.class);
        Example.Criteria criteria1 = example1.createCriteria();
        criteria1.andEqualTo(SysRoleMenu.Field.roleCode, roleCode);
        sysRoleMenuMapper.deleteByExample(example1);

        //删除角色-按钮
        Example example2 = new Example(SysRoleButton.class);
        Example.Criteria criteria2 = example2.createCriteria();
        criteria2.andEqualTo(SysRoleButton.Filed.roleCode, roleCode);
        sysRoleButtonMapper.deleteByExample(example2);

        int affectCount = sysRoleMapper.deleteByExample(example);

        // ====== redis ======
        if (affectCount > 0) {
            // 删除角色 redis_role_status
            sysRedisAuthService.delRedisRoleStatus(roleCode);

            // redis_role_permission (删除可用角色-可用菜单-可用按钮)
            sysRedisAuthService.delRedisRolePermissionFromRedis(roleCode,null,null);
        }
        return affectCount;
    }


    @Override
    public Set<String> getRolePermissionFromRedis(String username, String menuCode) {
        OnlineUserDTO onlineUserDTO = sysRedisAuthService.getRedisUserToken(username);
        return sysRedisAuthService.getRedisAuthButton(onlineUserDTO.getRoleCode(),menuCode);
    }

    @Override
    public Set<String> getMenuPermissionFromRedis(String menuCode) {
        return sysRedisAuthService.getRedisMenuButton(menuCode);
    }

    @Override
    public List<SysRole> getAllSysRole() {
        Example example = new Example(SysRole.class);
        return sysRoleMapper.selectByExample(example);
    }
}
